package com.gao.api.gate.quick.proto.http;

import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.HttpContent;
import io.netty.handler.codec.http.LastHttpContent;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.cookie.Cookie;
import org.apache.commons.lang3.StringUtils;

import java.net.SocketAddress;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * <p></p>
 *
 * @author gaoshuangwen
 * @since 2022/01/13 14:54
 */
public class AbstractRequest implements Request {

    private RequestContext rtx;
    private ChannelHandlerContext ctx;
    private String requestIdent;
    private String version;
    private HttpMethod method;
    private String uri;
    private String schema;
    private Headers headers;
    private SocketAddress localAddress;
    private SocketAddress remoteAddress;
    private boolean hasBody;
    private HttpBody body;

    /**
     * 唯一数据源 io.netty.handler.codec.http.HttpRequest
     *
     * @param httpRequest
     */
    public AbstractRequest(io.netty.handler.codec.http.HttpRequest httpRequest, ChannelHandlerContext ctx) {
        this.ctx = ctx;
        this.requestIdent = ctx.channel().id().asLongText();
        this.version = httpRequest.protocolVersion().text();
        this.method = httpRequest.method();
        this.uri = httpRequest.uri();
        this.headers = Headers.build(httpRequest.headers());
        this.localAddress = ctx.channel().localAddress();
        this.remoteAddress = ctx.channel().remoteAddress();
        buildBody(httpRequest);
    }

    @Override
    public RequestContext getContext() {
        return rtx;
    }

    @Override
    public String requestIdent() {
        return requestIdent;
    }

    @Override
    public String version() {
        return version;
    }

    @Override
    public HttpMethod method() {
        return method;
    }

    @Override
    public String uri() {
        return uri;
    }

    @Override
    public String scheme() {
        return schema;
    }

    @Override
    public Headers headers() {
        return headers;
    }

    @Override
    public Map<String, Cookie> cookies() {
        return null;
    }

    @Override
    public SocketAddress remoteAddress() {
        return remoteAddress;
    }

    @Override
    public SocketAddress localAddress() {
        return localAddress;
    }

    @Override
    public boolean hasBody() {
        return hasBody;
    }

    @Override
    public HttpBody body() {
        return body;
    }

    @Override
    public void setBody(HttpContent chunk) {
        body.loading(chunk);
    }

    @Override
    public boolean hasCompleteBody() {
        List<HttpContent> chunks = body.getChunks();
        for (HttpContent chunk : chunks) {
            if (chunk instanceof LastHttpContent) {
                return true;
            }
        }
        return false;
    }

    @Override
    public void releaseBody() {

        rtx.release(body);

    }

    private void buildBody(io.netty.handler.codec.http.HttpRequest httpRequest){

        String length = this.headers.first("Content-Length");
        this.hasBody = StringUtils.isNotBlank(length);
        if(this.hasBody){
            this.body = new HttpBody(Integer.parseInt(length));
            return;
        }
        // chunk
        List<String> strings = this.headers.get("Transfer-Encoding");
        if(strings == null){
            this.hasBody = false;
            return;
        }
        for (String string : strings) {
            if("chunked".equalsIgnoreCase(string)){
                this.hasBody = true;
                this.body = new HttpBody();
                return;
            }
        }
    }
}
